install.packages("DataExplorer")
install.packages("Hmisc")
install.packages("BBmisc")
install.packages("vioplot")
install.packages("moments")
install.packages("readxl")
install.packages("datetime")
install.packages("lubridate")
install.packages("cluster")
install.packages("factoextra")
install.packages("gridExtra")
install.packages("purrr")
install.packages("arules")
install.packages("arulesViz")
install.packages("data.table")
library(DataExplorer)
library(Hmisc)
## Loading required package: lattice
## Loading required package: survival
## Loading required package: Formula
## Loading required package: ggplot2
##
## Attaching package: 'Hmisc'
## The following objects are masked from 'package:base':
##
## format.pval, units
library(BBmisc)
##
## Attaching package: 'BBmisc'
## The following object is masked from 'package:Hmisc':
##
## %nin%
## The following object is masked from 'package:base':
##
## isFALSE
library(vioplot)
## Loading required package: sm
## Package 'sm', version 2.2-5.7: type help(sm) for summary information
##
## Attaching package: 'sm'
## The following object is masked from 'package:BBmisc':
##
## pause
## Loading required package: zoo
##
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
##
## as.Date, as.Date.numeric
library(moments)
library(readxl)
library(dplyr)
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:BBmisc':
##
## coalesce, collapse
## The following objects are masked from 'package:Hmisc':
##
## src, summarize
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(datetime)
library(lubridate)
## Loading required package: timechange
##
## Attaching package: 'lubridate'
## The following objects are masked from 'package:base':
##
## date, intersect, setdiff, union
library(factoextra)
## Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
library(cluster)
library(gridExtra)
##
## Attaching package: 'gridExtra'
## The following object is masked from 'package:dplyr':
##
## combine
library(purrr)
library(arules)
## Loading required package: Matrix
##
## Attaching package: 'arules'
## The following object is masked from 'package:dplyr':
##
## recode
## The following objects are masked from 'package:base':
##
## abbreviate, write
library(arulesViz)
library(data.table)
##
## Attaching package: 'data.table'
## The following object is masked from 'package:purrr':
##
## transpose
## The following objects are masked from 'package:lubridate':
##
## hour, isoweek, mday, minute, month, quarter, second, wday, week,
## yday, year
## The following objects are masked from 'package:dplyr':
##
## between, first, last
# Lê o ficheiro chamado "Online Retail.xlsx" e coloca os dados na variável "my_data".
# Em seguida, o comando "str (my_data)" descreve resumidamente os dados armazenados na variável "my_data",
# incluindo o número de observações e colunas, e os nomes e tipos de variáveis.
my_data <- read_excel("Online Retail.xlsx")
str(my_data)
## tibble [541,909 × 8] (S3: tbl_df/tbl/data.frame)
## $ InvoiceNo : chr [1:541909] "536365" "536365" "536365" "536365" ...
## $ StockCode : chr [1:541909] "85123A" "71053" "84406B" "84029G" ...
## $ Description: chr [1:541909] "WHITE HANGING HEART T-LIGHT HOLDER" "WHITE METAL LANTERN" "CREAM CUPID HEARTS COAT HANGER" "KNITTED UNION FLAG HOT WATER BOTTLE" ...
## $ Quantity : num [1:541909] 6 6 8 6 6 2 6 6 6 32 ...
## $ InvoiceDate: POSIXct[1:541909], format: "2010-12-01 08:26:00" "2010-12-01 08:26:00" ...
## $ UnitPrice : num [1:541909] 2.55 3.39 2.75 3.39 3.39 7.65 4.25 1.85 1.85 1.69 ...
## $ CustomerID : num [1:541909] 17850 17850 17850 17850 17850 ...
## $ Country : chr [1:541909] "United Kingdom" "United Kingdom" "United Kingdom" "United Kingdom" ...
# Mostra as primeiras 10 linhas do dataset my_data.
head(my_data, 10)
## # A tibble: 10 × 8
## InvoiceNo Stock…¹ Descr…² Quant…³ InvoiceDate UnitP…⁴ Custo…⁵ Country
## <chr> <chr> <chr> <dbl> <dttm> <dbl> <dbl> <chr>
## 1 536365 85123A WHITE … 6 2010-12-01 08:26:00 2.55 17850 United…
## 2 536365 71053 WHITE … 6 2010-12-01 08:26:00 3.39 17850 United…
## 3 536365 84406B CREAM … 8 2010-12-01 08:26:00 2.75 17850 United…
## 4 536365 84029G KNITTE… 6 2010-12-01 08:26:00 3.39 17850 United…
## 5 536365 84029E RED WO… 6 2010-12-01 08:26:00 3.39 17850 United…
## 6 536365 22752 SET 7 … 2 2010-12-01 08:26:00 7.65 17850 United…
## 7 536365 21730 GLASS … 6 2010-12-01 08:26:00 4.25 17850 United…
## 8 536366 22633 HAND W… 6 2010-12-01 08:28:00 1.85 17850 United…
## 9 536366 22632 HAND W… 6 2010-12-01 08:28:00 1.85 17850 United…
## 10 536367 84879 ASSORT… 32 2010-12-01 08:34:00 1.69 13047 United…
## # … with abbreviated variable names ¹StockCode, ²Description, ³Quantity,
## # ⁴UnitPrice, ⁵CustomerID
# Mostra as últimas 10 linhas do dataset my_data.
tail(my_data, 10)
## # A tibble: 10 × 8
## InvoiceNo Stock…¹ Descr…² Quant…³ InvoiceDate UnitP…⁴ Custo…⁵ Country
## <chr> <chr> <chr> <dbl> <dttm> <dbl> <dbl> <chr>
## 1 581587 22726 ALARM … 4 2011-12-09 12:50:00 3.75 12680 France
## 2 581587 22730 ALARM … 4 2011-12-09 12:50:00 3.75 12680 France
## 3 581587 22367 CHILDR… 8 2011-12-09 12:50:00 1.95 12680 France
## 4 581587 22629 SPACEB… 12 2011-12-09 12:50:00 1.95 12680 France
## 5 581587 23256 CHILDR… 4 2011-12-09 12:50:00 4.15 12680 France
## 6 581587 22613 PACK O… 12 2011-12-09 12:50:00 0.85 12680 France
## 7 581587 22899 CHILDR… 6 2011-12-09 12:50:00 2.1 12680 France
## 8 581587 23254 CHILDR… 4 2011-12-09 12:50:00 4.15 12680 France
## 9 581587 23255 CHILDR… 4 2011-12-09 12:50:00 4.15 12680 France
## 10 581587 22138 BAKING… 3 2011-12-09 12:50:00 4.95 12680 France
## # … with abbreviated variable names ¹StockCode, ²Description, ³Quantity,
## # ⁴UnitPrice, ⁵CustomerID
# Descrição resumida dos dados "my_data", incluindo estatísticas resumidas, como a média, mediana, desvio padrão e quartis para
# variáveis numéricas, e contagem e frequência para variáveis categóricas.
summary(my_data)
## InvoiceNo StockCode Description Quantity
## Length:541909 Length:541909 Length:541909 Min. :-80995.00
## Class :character Class :character Class :character 1st Qu.: 1.00
## Mode :character Mode :character Mode :character Median : 3.00
## Mean : 9.55
## 3rd Qu.: 10.00
## Max. : 80995.00
##
## InvoiceDate UnitPrice CustomerID
## Min. :2010-12-01 08:26:00.00 Min. :-11062.06 Min. :12346
## 1st Qu.:2011-03-28 11:34:00.00 1st Qu.: 1.25 1st Qu.:13953
## Median :2011-07-19 17:17:00.00 Median : 2.08 Median :15152
## Mean :2011-07-04 13:34:57.16 Mean : 4.61 Mean :15288
## 3rd Qu.:2011-10-19 11:27:00.00 3rd Qu.: 4.13 3rd Qu.:16791
## Max. :2011-12-09 12:50:00.00 Max. : 38970.00 Max. :18287
## NA's :135080
## Country
## Length:541909
## Class :character
## Mode :character
##
##
##
##
# Visualizar os nomes das colunas.
plot_str(my_data)
# Verificação dos valores negativos.
boxplot(my_data$Quantity,my_data$UnitPrice)

# Contamos aqui todos os NA's existentes na Coluna de CustomerID.
sum(is.na(my_data$CustomerID))
## [1] 135080
# Visto que vamos iniciar a manipulação e tratamento, deixaremos iremos guardar a variavel my_data com os dados
# originais e atribuiremos a outra variavel os dados para podermos efetuar transformações.
# Removemos os NA's e confirmamos com o sum para verificar que a quantidade de NA's é 0.
dataset <- my_data
dataset <- na.omit(dataset)
sum(is.na(dataset$CustomerID))
## [1] 0
# Verificamos a quantidade de valores negativos nas colunas Quantity e UnitPrice.
sum(dataset$Quantity<0)
## [1] 8905
sum(dataset$UnitPrice<=0.0)
## [1] 40
# Filtramos o conjunto de dados "dataset" onde a quantidade (Quantity) é maior que zero e o preço unitário (UnitPrice) é maior que zero.
# Vai então remover as linhas onde a quantidade ou preço unitário é negativo ou zero.
# Depois executamos o sum para confirmar a operação.
dataset <- filter(dataset, dataset$Quantity > 0, dataset$UnitPrice > 0.0)
sum(dataset$Quantity<0)
## [1] 0
sum(dataset$UnitPrice<=0.0)
## [1] 0
# Verificar a correlação entre as variáveis do conjunto de dados do "dataset".
plot_correlation(dataset)
## Warning in dummify(data, maxcat = maxcat): Ignored all discrete features since
## `maxcat` set to 20 categories!

# Confirmação de que não existem valores nulos.
any(is.null(dataset))
## [1] FALSE
# Remove todas as linhas do conjunto de dados que contenham valores ausentes (NA).
# A função "dim()" imprime o número de linhas e colunas do conjunto de dados "dataset".
dataset = na.omit(dataset)
# "unique()" para remover as linhas duplicadas do conjunto de dados "dataset".
dim(unique(dataset))[1]
## [1] 392692
# Cria uma nova coluna chamada "date", no conjunto de dados "dataset", extraída da coluna "InvoiceDate", e seleciona somente a data.
dataset$date <- sapply(as.character(dataset$InvoiceDate), FUN = function(x) {strsplit(x, split = '[ ]')[[1]][1]})
# Cria uma nova coluna chamada "date", no conjunto de dados "dataset", extraída da coluna "InvoiceDate", e seleciona somente a tempo.
dataset$time <- sapply(as.character(dataset$InvoiceDate), FUN = function(x) {strsplit(x, split = '[ ]')[[1]][2]})
# Cria uma nova coluna chamada "date", no conjunto de dados "dataset", extraída da coluna "InvoiceDate", e seleciona somente o mês.
dataset$month <- sapply(as.character(dataset$InvoiceDate), FUN = function(x) {strsplit(x, split = '[-]')[[1]][2]})
# Cria uma nova coluna chamada "date", no conjunto de dados "dataset", extraída da coluna "InvoiceDate", e seleciona somente o ano.
dataset$year <- sapply(as.character(dataset$InvoiceDate), FUN = function(x) {strsplit(x, split = '[-]')[[1]][1]})
# Cria uma nova coluna chamada "date", no conjunto de dados "dataset", extraída da coluna "InvoiceDate", e seleciona somente a hora do dia da compra.
dataset$hourOfDay <- sapply(dataset$time, FUN = function(x) {strsplit(x, split = '[:]')[[1]][1]})
# Função "mutate()" adiciona "TotalSales" ao conjunto de dados "dataset" com os valores calculados, multiplicando "Quantity" e "UnitPrice".
dataset = mutate(dataset, TotalSales = Quantity*UnitPrice)
# Nova coluna chamada "dayOfWeek", no conjunto de dados "dataset", com o dia da semana extraído da coluna "InvoiceDate", usando a função "wday()" com o parametro
# "label = TRUE", o que retorna o dia da semana como um Char.
dataset$dayOfWeek <- wday(dataset$InvoiceDate)
# Converter a coluna "Country", "month", "year", "hourOfDay" e "dayOfWeek" em fator, usando a função "as.factor()".
dataset$Country <- as.factor(dataset$Country)
dataset$month <- as.factor(dataset$month)
dataset$year <- as.factor(dataset$year)
# Altera os níveis da coluna para somente 2010 e 2011 com "levels()".
levels(dataset$year) <- c(2010,2011)
hourOfDay <- as.factor(dataset$hourOfDay)
dataset$dayOfWeek <- as.factor(dataset$dayOfWeek)
# Criando uma variável chamada "max_date" e armazenando a data mais recente, presente na coluna "InvoiceDate", utilizando a função "max()" com o parametro "na.rm = TRUE" para remover os valores ausentes.
max_date <- max(dataset$InvoiceDate, na.rm = TRUE)
# Função "mutate()" para adicionar uma nova coluna chamada "Diff" ao conjunto de dados "dataset", e preenchendo-a com a diferença, em dias, entre cada data na coluna "InvoiceDate", e a data mais recente armazenada na variável "max_date", utilizando a função "difftime()" com o parametro "units = "days"".
dataset = mutate(dataset, Diff = difftime(max_date, InvoiceDate, units = "days"))
# Função "floor()" para arredondar para baixo o valor de cada célula da coluna "Diff".
dataset$Diff <- floor(dataset$Diff)
# Recência, Frequência, Monetário = RFM
# Novo conjunto de dados chamado "RFM" que agrupa o conjunto de dados "dataset" por "CustomerID", utilizando a função "group_by()" e calculando a frequência (Frequency) de compras de cada cliente, o valor monetário total (Monetary) das compras de cada cliente e a recência (Recency) da última compra de cada cliente, utilizando as funções "n()" "sum()" e "min()" respetivamente.
RFM <- summarise(group_by(dataset,CustomerID),Frequency = n(), Monetary = sum(TotalSales), Recency = min(Diff))
# Conversão da coluna "Recency" em tipo numérico, utilizando "as.numeric()".
RFM$Recency <- as.numeric(RFM$Recency)
# Substituindo todos os valores ausentes (NA) na coluna "Monetary" por 0, utilizando "RFM$Monetary[is.na(RFM$Monetary)] <- 0".
RFM$Monetary[is.na(RFM$Monetary)] <- 0
# "summary()" Resumo estatístico das colunas "Frequency", "Monetary" e "Recency".
summary(RFM)
## CustomerID Frequency Monetary Recency
## Min. :12346 Min. : 1.00 Min. : 3.75 Min. : 0.00
## 1st Qu.:13813 1st Qu.: 17.00 1st Qu.: 307.42 1st Qu.: 17.00
## Median :15300 Median : 41.00 Median : 674.48 Median : 50.00
## Mean :15300 Mean : 91.72 Mean : 2054.27 Mean : 91.54
## 3rd Qu.:16779 3rd Qu.: 100.00 3rd Qu.: 1661.74 3rd Qu.:141.00
## Max. :18287 Max. :7847.00 Max. :280206.02 Max. :373.00
# Gráfico de correlação entre Frequency, Monetary e Recency.
plot_correlation(RFM)
# Criação de um gráfico de barras intitulado “2010 vs 2011”, com o dataset especificado. O eixo “X” representa os anos indicados e o “Y” as transações.
ggplot(dataset, aes(year)) + geom_bar(aes(fill = "year")) + labs(title = "2010 vs 2011", x = "Ano", y = "Transações") + guides(fill = FALSE) + scale_x_discrete(labels = c("2010" = "2010", "2011" = "2011")) + theme_bw()
## Warning: The `<scale>` argument of `guides()` cannot be `FALSE`. Use "none" instead as
## of ggplot2 3.3.4.
# Criação da tabela “Transactions_per_Country”. Primeiro é aplicado o group_by (dataset, Country) para agrupar as transações por país.
# Em seguida, é aplicado o summarise para contar o número de transações por país.
# Depois, é aplicado o arrange para ordenar a tabela de forma decrescente, pelo número de transações.
# Por fim, é aplicado o top_n para selecionar os 10 países com o maior número de transações, sendo as colunas da tabela renomeadas para "Country" e "Number of Transactions".
Transactions_per_Country <- top_n(arrange(summarise(group_by(dataset, Country), 'Number of Transcations' = n()), desc(`Number of Transcations`)), 10)
## Selecting by Number of Transcations
names(Transactions_per_Country) <- c("Country", "Number of Transactions")
# Criação do gráfico de barras "5 melhores Países por número de transações”, com os rótulos "Países" e "Número de Transações" para os eixos x e y,
# respetivamente, exibindo os 5 primeiros países com o maior número de transações.
Transaction_per_Country_plot <- ggplot(head(Transactions_per_Country,5), aes(x = reorder(Country,-`Number of Transactions`), y = `Number of Transactions`)) + geom_bar(stat = 'identity', fill = "Brown") +
geom_text(aes(label = `Number of Transactions`)) +
ggtitle('5 melhores Países por número de transações') + xlab('Países') +
ylab('Número de Transações') +
theme_bw()
print(Transaction_per_Country_plot)
# Criação do gráfico de barras "Receita por dia da Semana", com os rótulos "Dia da Semana" e "Receita (€)" para os eixos x e y, respetivamente.
# Primeiro, é aplicado o group_by(dataset, dayOfWeek) para agrupar as transações por dia da semana.
# Depois, é aplicado o summarise para somar as vendas totais, por dia da semana.
# Aplicando o ggplot, o gráfico é criado. Aplicando o geom_bar as barras do gráfico são desenhadas e o parametro stat = 'identity' mostra a receita total como valores absolutos.
# O objetivo deste gráfico é mostrar a receita total, por dia da semana, ajudando desta forma a percebermos quais são os dias da semana que geram mais receita.
suppressWarnings(ggplot(summarise(group_by(dataset, dayOfWeek), revenue = sum(TotalSales)), aes(x = dayOfWeek, y = revenue)) + geom_bar(stat = 'identity', fill = 'Brown') + labs(x = 'Dia da Semana', y = 'Receita Euro', title = 'Receita por dia da Semana') + theme_bw())
# Criação do gráfico de barras "Receita por mês de determinado ano", com os rótulos "Mês" e "Receita (€)" para os eixos x e y, respetivamente.
# Primeiro, é aplicado o group_by(dataset, month) para agrupar as transações por mês.
# Depois, é aplicado o summarise para somar as vendas totais por mês.
# Aplicando o ggplot, o gráfico é criado. Aplicando o geom_bar as barras do gráfico são desenhadas e o parametro stat = 'identity' mostra a receita total como valores absolutos.
# Este gráfico mostra a receita total, por mês, de determinado ano, que ajuda a entender quais os meses que geram mais receita.
suppressWarnings(ggplot(summarise(group_by(dataset, month), revenue = sum(TotalSales)), aes(x = month, y = revenue)) + geom_bar(stat = 'identity', fill = 'Brown') + labs(x = 'Mês', y = 'Receita Euro', title = 'Receita por mês de determinado ano') + theme_bw())
# Criação do gráfico de barras "Transacoes por hora do dia", com os rótulos "Hora do Dia" e "Transações" para os eixos x e y, respetivamente.
# Primeiro, é aplicado o group_by(dataset, hourOfDay) para agrupar as transações por hora do dia.
# Depois, é aplicado o summarise para contar o número de transações distintas, por hora do dia, utilizando n_distinct(InvoiceNo).
# Aplicando o ggplot, o gráfico é criado. Aplicando o geom_bar as barras do gráfico são desenhadas e o parametro stat = 'identity' mostra o número de transações distintas como valores absolutos.
# O objetivo deste gráfico é mostrar o número de transações distintas, por hora do dia, o que ajuda a entender a que horas as transações são mais frequentes.
suppressWarnings(ggplot(summarise(group_by(dataset, hourOfDay), transactions = n_distinct(InvoiceNo)), aes(x = hourOfDay, y = transactions)) + geom_bar(stat = 'identity', fill = "Brown") + labs(x = 'Hora do Dia', y = 'Transações Euros', title = 'Transacoes por hora do dia') + theme_bw())
# Criação do dataframe “RFM”, a partir de uma variável “RFM” já existente.
# De seguida, são definidos os nomes das linhas do dataframe, como o valor da coluna "CustomerID" do mesmo, sendo depois removida a primeira coluna do dataframe.
# Por fim, os valores do dataframe são escalados e o resultado é guardado num novo dataframe, chamado “rfm_scaled”.
RFM <- data.frame(RFM)
row.names(RFM) <- RFM$CustomerID
RFM <- RFM[,-1]
RFM_scaled <- scale(RFM)
RFM_scaled <- data.frame(RFM_scaled)
# Utilização da função "fviz_nbclust”, para visualizar o número ideal de clusters para o dataframe “RFM_scaled”, utilizando o algoritmo "kmeans" e o método "wss" (soma dos quadrados dentro do grupo).
# É adicionada uma linha vertical ao gráfico, na posição “x = 3”, que é utilizada como referência para comparar o número de clusters sugeridos pelo gráfico, com outros valores.
fviz_nbclust(RFM_scaled, kmeans, method = "wss", linecolor = "Brown") + geom_vline(xintercept = 3, linetype = 2)
# Utilização da função "fviz_nbclust”, para visualizar o grupo de dados, juntamente com o algoritmo "kmeans”, aplicado aos dados do dataframe "RFM_scaled".
# O método de avaliação utilizado é o "silhouette”.
fviz_nbclust(RFM_scaled, kmeans, method = "silhouette", linecolor = "Brown")
# Utilização da função "kmeans" para agrupar os dados "RFM_scaled" em 3 clusters. O número de vezes que o algoritmo é iniciado a partir de uma configuração aleatória é 25, definido pelo argumento "nstart”. A saída é guardada na variável "k3".
k3 <- kmeans(RFM_scaled, centers = 3, nstart = 25)
# Utilização da função "kmeans" para agrupar os dados "RFM_scaled" em 2 clusters. O número de vezes que o algoritmo é iniciado a partir de uma configuração aleatória é 25, definido pelo argumento "nstart”. A saída é guardada na variável "k2”.
k2 <- kmeans(RFM_scaled, centers = 2, nstart = 25)
# Utilização da função "kmeans" para agrupar os dados "RFM_scaled" em 4 clusters. O número de vezes que o algoritmo é iniciado a partir de uma configuração aleatória é 25, definido pelo argumento "nstart”. A saída é guardada na variável "k4”.
k4 <- kmeans(RFM_scaled, centers = 4, nstart = 25)
# Utilização da função "fviz_cluster" para visualizar o grupo de dados armazenado na variável "k3”. É utilizada, igualmente, a geometria "point" para representar os pontos dos dados.
# O dataframe utilizado é o "RFM_scaled" e o tamanho dos pontos é definido como 0,2. Além disso, é adicionado o título "k = 3" à visualização.
fviz_cluster(k3, geom = "point", data = RFM_scaled, pointsize = 0.2) + ggtitle("k = 3") + theme_bw()
# Utilização da função "fviz_cluster" para visualizar o grupo de dados armazenado na variável "k4”. É utilizada, igualmente, a geometria "point" para representar os pontos dos dados.
# O dataframe utilizado é o "RFM_scaled" e o tamanho dos pontos é definido como 0,2. Além disso, é adicionado o título "k = 4" à visualização.
fviz_cluster(k4, geom = "point", data = RFM_scaled, pointsize = 0.2) + ggtitle("k = 4") + theme_bw()
# Utilização da função "fviz_cluster" para visualizar o grupo de dados guardado na variável "k2", utilizando os dados do dataframe "RFM_scaled".
# O tipo de elipse utilizado para representar os clusters é o "convex”, e o argumento "repel" está definido como "T" (verdadeiro), o que faz com que os rótulos sejam afastados para evitar sobreposição.
fviz_cluster(k2, data=RFM_scaled, ellipse.type = "convex", repel = T)
## Warning: ggrepel: 4328 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps
# Utilização da função "fviz_cluster" para visualizar o grupo de dados guardado na variável "k3", utilizando os dados do dataframe "RFM_scaled".
# O tipo de elipse utilizado para representar os clusters é o "convex”, e o argumento "repel" está definido como "T" (verdadeiro), o que faz com que os rótulos sejam afastados para evitar sobreposição.
fviz_cluster(k3, data=RFM_scaled, ellipse.type = "convex", repel = T)
## Warning: ggrepel: 4328 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps
# Utilização da função "fviz_cluster" para visualizar o grupo de dados guardado na variável "k4", utilizando os dados do dataframe "RFM_scaled".
# O tipo de elipse utilizado para representar os clusters é o "convex”, e o argumento "repel" está definido como "T" (verdadeiro), o que faz com que os rótulos sejam afastados para evitar sobreposição.
fviz_cluster(k4, data=RFM_scaled, ellipse.type = "convex", repel = T)
## Warning: ggrepel: 4328 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps
# Utilização da função "silhouette”, para calcular a medida da silhueta para cada ponto do dado, comparando a semelhança de um ponto dentro do seu cluster, com a semelhança desse ponto com os outros clusters.
# Utilização da função "fviz_silhouette” para visualizar esses valores de silhueta. O resultado é uma visualização que mostra a distribuição dos valores de silhueta para cada cluster, onde os valores próximos de 1 indicam que os pontos estão bem agrupados, e os valores próximos de -1 indicam que os pontos estão mal agrupados.
# Avaliar e visualizar o quão bem os dados do dataframe "RFM_scaled" estão agrupados no modelo armazenado na variável "k3".
sil <- silhouette(k3$cluster, dist(RFM_scaled))
fviz_silhouette(sil)
## cluster size ave.sil.width
## 1 1 1080 0.59
## 2 2 3245 0.61
## 3 3 13 0.09
# Avaliar e visualizar o quão bem os dados do dataframe "RFM_scaled" estão agrupados no modelo armazenado na variável "k4".
sil <- silhouette(k4$cluster, dist(RFM_scaled))
fviz_silhouette(sil)
## cluster size ave.sil.width
## 1 1 289 0.13
## 2 2 12 0.04
## 3 3 2982 0.67
## 4 4 1055 0.58
# Avaliar e visualizar o quão bem os dados do dataframe "RFM_scaled" estão agrupados no modelo armazenado na variável "k2".
sil <- silhouette(k2$cluster, dist(RFM_scaled))
fviz_silhouette(sil)
## cluster size ave.sil.width
## 1 1 13 0.09
## 2 2 4325 0.93
# Criação de uma nova tabela com os dados do dataframe "RFM”. É adicionada uma coluna "ClusterId" com os identificadores de cluster gerados pelo modelo armazenado na variável "k3".
# A função "cbind" é utilizada para combinar as colunas do dataframe "RFM" e os identificadores de cluster.
res <- cbind(RFM, ClusterId = k3$cluster)
# A função "as.data.frame" é utilizada para converter a tabela combinada para um dataframe. A saída é guardada na variável "res".
res <- as.data.frame(res)
# Utilização da biblioteca “ggplot2” para criar um gráfico, que compara as três diferentes colunas abaixo indicadas, entre os diferentes clusters armazenados na coluna "ClusterId" do dataframe "res".
# O argumento "group" é utilizado para agrupar os dados, de acordo com o “ClusterId”, e o argumento "fill" é utilizado para colorir os gráficos, de acordo com o “ClusterId”.
# A função "geom_boxplot" é utilizada para criar o gráfico, em formato de caixa, e o argumento "show.legend" é definido como "FALSE" para ocultar a legenda.
# A função "scale_fill_brewer" é utilizada para definir o conjunto de cores "Reds" para os clusters.
# A função “ggplot” é utilizada para especificar o dataframe "res" como fonte de dados, e mapear as colunas "ClusterId" e "Frequency" para o eixo x e y respetivamente.
a <- ggplot(res, aes(x = ClusterId, y = Frequency, group = ClusterId, fill = as.factor(ClusterId))) +
geom_boxplot(show.legend = FALSE) + theme_bw() + scale_fill_brewer(palette = "Reds")
# A função “ggplot” é utilizada para especificar o dataframe "res" como fonte de dados, e mapear as colunas "ClusterId" e "Monetary" para o eixo x e y respetivamente.
b <- ggplot(res, aes(x = ClusterId, y = Monetary, group = ClusterId, fill = as.factor(ClusterId))) +
geom_boxplot(show.legend = FALSE) + theme_bw() + scale_fill_brewer(palette = "Reds")
# A função “ggplot” é utilizada para especificar o dataframe "res" como fonte de dados, e mapear as colunas "ClusterId" e "Recency" para o eixo x e y respetivamente.
c <- ggplot(res, aes(x = ClusterId, y = Recency, group = ClusterId, fill = as.factor(ClusterId))) +
geom_boxplot(show.legend = FALSE) + theme_bw() + scale_fill_brewer(palette = "Reds")
# Utilização da função "grid.arrange" que organiza os gráficos "a", "b" e "c" numa tabela com 3 colunas.
grid.arrange(a,b,c, ncol = 3)
# Utilização da função "fviz_nbclust" para visualizar o grupo de dados do dataframe “RFM_scaled”, e utilizando o método "hcut" e a medida "wss" para determinar o número ideal de clusters.
# É adicionada uma linha vertical com interceção em 3, utilizando a função "geom_vline" e o tipo de linha 2.
fviz_nbclust(RFM_scaled, FUN = hcut, method = "wss", linecolor = "Brown") + geom_vline(xintercept = 3, linetype = 2) + theme_bw()
# Utilização da função "fviz_nbclust" para visualizar o grupo de dados do dataframe “RFM_scaled”, e utilizando o método "hcut" e a medida "silhouette" para determinar o número ideal de clusters.
fviz_nbclust(RFM_scaled, FUN = hcut, method = "silhouette", linecolor = "Brown") + theme_bw()
## Hierarchical Clustering
#HC aglomerante com hclust. Primeiro calculamos os valores dissimilares com dist e depois alimentamos estes valores com hclust e especificamos o método de aglomeração a utilizar (isto é, "complete", "average", "single", "ward.D2"). Em seguida, traçamos o dendrograma.
euclidian_dist <- dist(RFM_scaled, method = "euclidean")
hc1 <- hclust(euclidian_dist, method = "single" )
hc2 <- hclust(euclidian_dist, method = "complete" )
hc3 <- hclust(euclidian_dist, method = "ward.D2" )
hc4 <- hclust(euclidian_dist, method = "average" )
m <- c( "average", "single", "complete", "ward")
names(m) <- c( "average", "single", "complete", "ward")
ac <- function(x) {
agnes(RFM_scaled, method = x)$ac
}
map_dbl(m, ac)
## average single complete ward
## 0.9976872 0.9955580 0.9984517 0.9992894
# Utilização da biblioteca "dendextend" para transformar o objeto "hc2" num dendrograma.
# De seguida, atribui-se as cores para as ramificações do dendrograma, com base em 3 grupos (k = 3), utilizando a função "color_branches”.
# Por fim, realiza-se o dendrograma com as cores atribuídas.
library(dendextend)
##
## ---------------------
## Welcome to dendextend version 1.16.0
## Type citation('dendextend') for how to cite the package.
##
## Type browseVignettes(package = 'dendextend') for the package vignette.
## The github page is: https://github.com/talgalili/dendextend/
##
## Suggestions and bug-reports can be submitted at: https://github.com/talgalili/dendextend/issues
## You may ask questions at stackoverflow, use the r and dendextend tags:
## https://stackoverflow.com/questions/tagged/dendextend
##
## To suppress this message use: suppressPackageStartupMessages(library(dendextend))
## ---------------------
##
## Attaching package: 'dendextend'
## The following object is masked from 'package:data.table':
##
## set
## The following object is masked from 'package:stats':
##
## cutree
hc2 <- as.dendrogram(hc2)
cd = color_branches(hc2,k = 3)
plot(cd)
# Utilização da biblioteca "dendextend" para transformar o objeto "hc3" num dendrograma.
# De seguida, atribui-se as cores para as ramificações do dendrograma, com base em 3 grupos (k = 3), utilizando a função "color_branches”.
# Por fim, realiza-se o dendrograma com as cores atribuídas.
hc3 <- as.dendrogram(hc3)
cd = color_branches(hc3,k = 3)
plot(cd)
# Utilização da biblioteca "dendextend" para transformar o objeto "hc3" num dendrograma.
# De seguida, atribui-se as cores para as ramificações do dendrograma, com base em 3 grupos (k = 3), utilizando a função "color_branches”.
# Por fim, realiza-se o dendrograma com as cores atribuídas.
hc3 <- as.dendrogram(hc3)
cd = color_branches(hc3,k = 3)
plot(cd)
# À função "ward.clust" é atribuído o valor de “cutree” do agrupamento hierárquico (hc3), para 3 grupos.
# De seguida, as colunas "RFM" e "ClusterId" são adicionadas ao "res1”, sendo convertidas para um dataframe.
ward.clust = cutree(hc3,k = 3)
res1 <- cbind(RFM, ClusterId = ward.clust)
res1 <- as.data.frame(res1)
# Criação de um gráfico, utilizando a biblioteca “ggplot2”, e utilizando os dados do dataframe "res1" e mapeando as colunas "ClusterId" (eixo x) e "Frequency" (eixo y) para o gráfico.
# São agrupados os dados pelo "ClusterId" e as caixas do gráfico são preenchidas com o conjunto de cores "Reds”, de acordo com o “ClusterId”.
# É utilizado um tema simples e não é exibida legenda.
a <- ggplot(res1, aes(x = ClusterId, y = Frequency, group = ClusterId, fill = as.factor(ClusterId))) +
geom_boxplot(show.legend = FALSE) + theme_minimal() + scale_fill_brewer(palette = "Reds")
# Criação de um gráfico, utilizando a biblioteca “ggplot2”, e utilizando os dados do dataframe "res1" e mapeando as colunas "ClusterId" (eixo x) e "Monetary" (eixo y) para o gráfico.
# São agrupados os dados pelo "ClusterId" e as caixas do gráfico são preenchidas com o conjunto de cores "Reds”, de acordo com o “ClusterId”.
# É utilizado um tema simples e não é exibida legenda.
b <- ggplot(res1, aes(x = ClusterId, y = Monetary, group = ClusterId, fill = as.factor(ClusterId))) +
geom_boxplot(show.legend = FALSE) + theme_minimal() + scale_fill_brewer(palette = "Reds")
# Criação de um gráfico, utilizando a biblioteca “ggplot2”, e utilizando os dados do dataframe "res1" e mapeando as colunas "ClusterId" (eixo x) e "Recency" (eixo y) para o gráfico.
# São agrupados os dados pelo "ClusterId" e as caixas do gráfico são preenchidas com o conjunto de cores "Reds”, de acordo com o “ClusterId”.
# É utilizado um tema simples e não é exibida legenda.
c <- ggplot(res1, aes(x = ClusterId, y = Recency, group = ClusterId, fill = as.factor(ClusterId))) +
geom_boxplot(show.legend = FALSE) + theme_minimal() + scale_fill_brewer(palette = "Reds")
# Utilização da função "grid.arrange" que organiza os gráficos "a", "b" e "c" numa tabela com 3 colunas.
grid.arrange(a,b,c, ncol = 3)
# Utilização da função "fviz_cluster" para visualizar os resultados do grupo “K-means”, com 3 clusters (k3), no conjunto de dados do dataframe “RFM_scaled”.
# O parametro "geom" é configurado como "point" para exibir cada ponto de dados num gráfico de dispersão.
# O título do gráfico é definido como "K-means Clustering”, usando a função "ggtitle".
fviz_cluster(k3, data = RFM_scaled, geom = "point") + ggtitle("K-means Clustering")
# Visualização dos clusters gerados pelo algoritmo de agrupamento hierárquico "ward”, utilizando os dados do dataframe "RFM_scaled”.
# A função "fviz_cluster" é utilizada para exibir os clusters como pontos.
# O título do gráfico é "Hierarchical Clustering".
fviz_cluster(list(data = RFM_scaled, cluster = ward.clust), geom = "point") + ggtitle("Hierarchical Clustering")
#K-means
# Agrupamento dos dados "res” pelo id de clusters "res$ClusterId”, e calculando a média dos valores para cada grupo.
# A função "aggregate" é usada para agrupar os dados e calcular a média, e a "by" é usada para especificar o grupo de colunas pelo qual os dados devem ser agrupados.
aggregate(res,by = list(res$ClusterId),FUN = mean)
## Group.1 Frequency Monetary Recency ClusterId
## 1 1 27.78796 637.3185 246.308333 1
## 2 2 103.08906 2028.8339 40.377196 2
## 3 3 2565.30769 126118.3100 3.692308 3
#Hierarchical
# Agrupamento dos dados "res1” pelo id de clusters "res1$ClusterId”, e calculando a média dos valores para cada grupo.
# A função "aggregate" é usada para agrupar os dados e calcular a média, e a "by" é usada para especificar o grupo de colunas pelo qual os dados devem ser agrupados.
aggregate(res1,by = list(res1$ClusterId),FUN = mean)
## Group.1 Frequency Monetary Recency ClusterId
## 1 1 112.33978 2277.6918 30.464298 1
## 2 2 33.25472 617.2412 209.183962 2
## 3 3 2650.18182 138176.7545 4.181818 3
# O comando "str(dataset)" exibe as informações estruturais sobre o dataset.
# De seguida, é criada uma variável chamada "united_kingdom”, que é uma cópia do dataset, e utiliza o pipe operator %>% e a função "mutate" para adicionar uma nova coluna chamada "InvoiceDate”, com as data formatadas como datetime.
# A função "as.datetime" é utilizada para formatar a coluna de data, de acordo com o parametro '%Y-%m-%d %H:%M:%S’.
str(dataset)
## tibble [397,884 × 16] (S3: tbl_df/tbl/data.frame)
## $ InvoiceNo : chr [1:397884] "536365" "536365" "536365" "536365" ...
## $ StockCode : chr [1:397884] "85123A" "71053" "84406B" "84029G" ...
## $ Description: chr [1:397884] "WHITE HANGING HEART T-LIGHT HOLDER" "WHITE METAL LANTERN" "CREAM CUPID HEARTS COAT HANGER" "KNITTED UNION FLAG HOT WATER BOTTLE" ...
## $ Quantity : num [1:397884] 6 6 8 6 6 2 6 6 6 32 ...
## $ InvoiceDate: POSIXct[1:397884], format: "2010-12-01 08:26:00" "2010-12-01 08:26:00" ...
## $ UnitPrice : num [1:397884] 2.55 3.39 2.75 3.39 3.39 7.65 4.25 1.85 1.85 1.69 ...
## $ CustomerID : num [1:397884] 17850 17850 17850 17850 17850 ...
## $ Country : Factor w/ 37 levels "Australia","Austria",..: 35 35 35 35 35 35 35 35 35 35 ...
## $ date : Named chr [1:397884] "2010-12-01" "2010-12-01" "2010-12-01" "2010-12-01" ...
## ..- attr(*, "names")= chr [1:397884] "2010-12-01 08:26:00" "2010-12-01 08:26:00" "2010-12-01 08:26:00" "2010-12-01 08:26:00" ...
## $ time : Named chr [1:397884] "08:26:00" "08:26:00" "08:26:00" "08:26:00" ...
## ..- attr(*, "names")= chr [1:397884] "2010-12-01 08:26:00" "2010-12-01 08:26:00" "2010-12-01 08:26:00" "2010-12-01 08:26:00" ...
## $ month : Factor w/ 12 levels "01","02","03",..: 12 12 12 12 12 12 12 12 12 12 ...
## ..- attr(*, "names")= chr [1:397884] "2010-12-01 08:26:00" "2010-12-01 08:26:00" "2010-12-01 08:26:00" "2010-12-01 08:26:00" ...
## $ year : Factor w/ 2 levels "2010","2011": 1 1 1 1 1 1 1 1 1 1 ...
## ..- attr(*, "names")= chr [1:397884] "2010-12-01 08:26:00" "2010-12-01 08:26:00" "2010-12-01 08:26:00" "2010-12-01 08:26:00" ...
## $ hourOfDay : Named chr [1:397884] "08" "08" "08" "08" ...
## ..- attr(*, "names")= chr [1:397884] "2010-12-01 08:26:00" "2010-12-01 08:26:00" "2010-12-01 08:26:00" "2010-12-01 08:26:00" ...
## $ TotalSales : num [1:397884] 15.3 20.3 22 20.3 20.3 ...
## $ dayOfWeek : Factor w/ 6 levels "1","2","3","4",..: 4 4 4 4 4 4 4 4 4 4 ...
## $ Diff : 'difftime' num [1:397884] 373 373 373 373 ...
## ..- attr(*, "units")= chr "days"
## - attr(*, "na.action")= 'omit' Named int [1:135080] 623 1444 1445 1446 1447 1448 1449 1450 1451 1452 ...
## ..- attr(*, "names")= chr [1:135080] "623" "1444" "1445" "1446" ...
united_kingdom <- dataset %>%
mutate(InvoiceDate = as.datetime(InvoiceDate, '%Y-%m-%d %H:%M:%S'))
# Criação de uma nova variável chamada "invoiced_items" que contém informações sobre os itens faturados, ao longo de várias etapas:
# 1 - Utilização do pipe operator %>% para aplicar as funções "group_by", "select" e "distinct" para agrupar os dados pelo número da fatura "InvoiceNo" e selecionar somente as colunas "InvoiceNo" e "Description", e remover todas as linhas duplicadas.
# 2 - Utilização da função "setDT" para converter o conjunto de dados num objeto do tipo data.table.
# 3 - Utilização da função "dcast" para transformar os dados numa tabela de contagem, com linhas como a InvoiceNo e colunas como as descrições de itens distintas. O primeiro parametro é o conjunto de dados, seguido de uma fórmula com a coluna de identificação das linhas (InvoiceNo) e colunas (rowid(InvoiceNo)).
# 4 - Utilização do "select" para remover a coluna "InvoiceNo”.
# Por fim, temos uma tabela com linhas como o número de fatura e as colunas como as descrições de itens distintos e os suas respetivas quantidades.
invoiced_items <- dcast(setDT(united_kingdom %>% group_by(InvoiceNo) %>% select(InvoiceNo, Description) %>% distinct(Description, .keep_all = TRUE)), InvoiceNo~rowid(InvoiceNo)) %>%
select(!InvoiceNo)
## Using 'Description' as value column. Use 'value.var' to override
# O conteúdo da variável "invoiced_items" é salvo num ficheiro CSV chamado "invoiced_items.csv".
# O ficheiro CSV não tem cabeçalho, aspas e os valores em falta aparecem como uma string vazia, graças aos parâmetros "quote = FALSE”, "row.names = FALSE”, "col.names = FALSE" e "na = ‘’”.
write.csv(invoiced_items, 'invoiced_items.csv', quote = FALSE, row.names = FALSE, col.names = FALSE, na = '')
# Leitura do ficheiro 'invoiced_items.csv’, sendo o mesmo guardado numa variável chamada 'transaction'.
# O formato especificado é 'basket' e o separador de colunas é ','.
suppressWarnings(transaction <- read.transactions('invoiced_items.csv', format = 'basket', sep = ','))
# A função "itemFrequencyPlot" gera um gráfico de frequência de itens a partir de uma transação de dados.
# O parâmetro "transaction" é a transação de dados que será utilizada para gerar o gráfico.
# O parâmetro "topN" especifica o número de itens mais frequentes a serem exibidos no gráfico.
# O parâmetro "type" especifica o tipo de frequência a ser exibida no gráfico, que pode ser "absolute" (absoluta) ou "relative" (relativa).
itemFrequencyPlot(transaction, topN = 10, type = 'absolute')
# A função "apriori" é utilizada para encontrar regras de associação nos dados da transação.
# O parâmetro "transaction" é a transação de dados que será utilizada para encontrar as regras de associação.
# O parâmetro "parameter" é uma lista de parâmetros adicionais que são utilizados para especificar os critérios de suporte, confiança e tamanho máximo das regras.
# O suporte é especificado com "supp" e é definido como 0.01, a confiança é especificada com "conf" e é definida como 0.85, e o tamanho máximo das regras é especificado com "maxlen" e é definido como 3.
# As regras encontradas são guardadas na variável "rules".
rules <- apriori(transaction, parameter = list(supp = 0.01, conf = 0.85, maxlen = 3))
## Apriori
##
## Parameter specification:
## confidence minval smax arem aval originalSupport maxtime support minlen
## 0.85 0.1 1 none FALSE TRUE 5 0.01 1
## maxlen target ext
## 3 rules TRUE
##
## Algorithmic control:
## filter tree heap memopt load sort verbose
## 0.1 TRUE TRUE FALSE TRUE 2 TRUE
##
## Absolute minimum support count: 185
##
## set item appearances ...[0 item(s)] done [0.00s].
## set transactions ...[8431 item(s), 18533 transaction(s)] done [0.12s].
## sorting and recoding items ... [502 item(s)] done [0.01s].
## creating transaction tree ... done [0.01s].
## checking subsets of size 1 2 3
## Warning in apriori(transaction, parameter = list(supp = 0.01, conf = 0.85, :
## Mining stopped (maxlen reached). Only patterns up to a length of 3 returned!
## done [0.01s].
## writing ... [12 rule(s)] done [0.00s].
## creating S4 object ... done [0.00s].
# A função "sort" é utilizada para classificar as regras de associação encontradas anteriormente.
# O parâmetro "rules" é a lista de regras de associação encontradas anteriormente.
# O parâmetro "by" é usado para especificar como as regras devem ser classificadas. Neste caso é "confidence" (confiança).
# O parâmetro "decreasing" é usado para especificar se a classificação deve ser em ordem decrescente ou crescente. Neste caso é "TRUE" (verdadeiro), o que indica que as regras serão classificadas em ordem decrescente, de acordo com o seu nível de confiança.
rules <- sort(rules, by = 'confidence', decreasing = TRUE)
# Gráfico do parâmetro "rules".
plot(rules)
## To reduce overplotting, jitter is added! Use jitter = 0 to prevent jitter.
# Realização do parâmetro "rules", em formato de gráfico.
plot(rules, method = 'graph')
inspect(sort(rules))
## lhs rhs support confidence coverage lift count
## [1] {PINK REGENCY TEACUP AND SAUCER,
## ROSES REGENCY TEACUP AND SAUCER} => {GREEN REGENCY TEACUP AND SAUCER} 0.01872336 0.8897436 0.02104354 26.46809 347
## [2] {PINK REGENCY TEACUP AND SAUCER,
## REGENCY CAKESTAND 3 TIER} => {GREEN REGENCY TEACUP AND SAUCER} 0.01300383 0.8731884 0.01489235 25.97560 241
## [3] {PINK REGENCY TEACUP AND SAUCER,
## REGENCY CAKESTAND 3 TIER} => {ROSES REGENCY TEACUP AND SAUCER} 0.01268008 0.8514493 0.01489235 22.31953 235
## [4] {SET 3 RETROSPOT TEA} => {SUGAR} 0.01181676 1.0000000 0.01181676 84.62557 219
## [5] {SUGAR} => {SET 3 RETROSPOT TEA} 0.01181676 1.0000000 0.01181676 84.62557 219
## [6] {SET 3 RETROSPOT TEA} => {COFFEE} 0.01181676 1.0000000 0.01181676 63.68729 219
## [7] {SUGAR} => {COFFEE} 0.01181676 1.0000000 0.01181676 63.68729 219
## [8] {SET 3 RETROSPOT TEA,
## SUGAR} => {COFFEE} 0.01181676 1.0000000 0.01181676 63.68729 219
## [9] {COFFEE,
## SET 3 RETROSPOT TEA} => {SUGAR} 0.01181676 1.0000000 0.01181676 84.62557 219
## [10] {COFFEE,
## SUGAR} => {SET 3 RETROSPOT TEA} 0.01181676 1.0000000 0.01181676 84.62557 219
## [11] {SHED} => {KEY FOB} 0.01122322 1.0000000 0.01122322 60.76393 208
## [12] {BACK DOOR} => {KEY FOB} 0.01041386 1.0000000 0.01041386 60.76393 193
Os clientes do Cluster 3 são os clientes com elevado volume de transacções, são compradores frequentes, e compradores que voltam recorrentemente em comparação com outros clientes, por isso são os mais importantes do ponto de vista comercial. Os clientes do Cluster 2 são os clientes com volume médio de transacções, em comparação com os melhores e os clientes fracos, sendo que são em termos de quantidade mais do que os melhores diria que a grosso modo tanto os clientes do Cluster 2 bem como os clientes do Cluster 3 serão os mais importantes para o negócio. Os clientes do Cluster 1 são os clientes com menor quantidade de transacções, são compradores pouco frequentes, e são compradores que voltam menos recorrentemente, portanto, menos importantes do ponto de vista comercial.
Hierárquico (3 Clusters) Os clientes do Cluster 3 são os clientes com elevado volume de transacções, são compradores frequentes, e compradores que voltam recorrentemente em comparação com outros clientes, por isso os mais importantes do ponto de vista comercial. Os clientes do Cluster 1 são os clientes com volume médio de transacções, em comparação com os melhores e os clientes fracos, sendo que são em termos de quantidade mais do que os melhores, diria que de grosso modo os clientes do Cluster 1 bem como os clientes do cluster 3 serão os mais importantes para o negócio. Os clientes do Cluster 2 são os clientes com menor quantidade de transacções, são compradores pouco frequentes, que voltam menos recorrentemente, portanto, menos importantes do ponto de vista comercial.
Sintetisando nas conclusões iniciais dos Clusters, achou-se que os Clientes estariam divididos entre Clientes Bons, Médios e Maus. No entanto após análise profunda o que é um mau cliente para o negócio? Qualquer pessoa que efetue uma compra no negócio é para nós importante e por consequência sendo o nosso principal objetivo vender o máximo de artigos possível, é lógico que para nós. Após uma análise mais profunda percebeu-se que a segmentação realizada anteriormente deixava de fazer qualquer sentido. Decidiu-se então padronizá-los por tipo de clientes e chegámos à conclusão de que o cluster 3 são as nossas “whales”, ou seja, os nossos melhores clientes aqueles que compram mais, com maior frequência e maior taxa de regresso à nossa loja. Atribuímos a estes um nível de importância 3 com a tentativa de os manter, não os esquecendo nunca, mas uma vez que já se encontram fidelizados, elaboramos campanhas mais esporádicas. Nos Clusters 2 no K-Means e 1 no Hierárquico de baixa taxa de regresso à loja, mas de alto valor monetário, notou-se que já foram clientes valiosos, mas desde então pararam. Chamámos-lhes de “Antigos”. Temos de promover arduamente o seu regresso utilizando possivelmente campanhas de loyalty e exclusivas para esta segmentação, obviamente não cometendo desigualdade relativamente ao setor anterior. Atribuímos a estes um nível de importância 1, tornando-se os mais importantes dos 3 Clusters. Quanto aos últimos Clusters 1 no K-Means e 2 no Hierárquico, chamaram-se de “Novos” pois são normalmente pessoas com alta taxa de regresso e baixa frequência. É um padrão de quem ainda se encontra a “avaliar” o terreno e ainda não está fidelizado, no entanto, achamos que um acompanhamento direcionado pode convertê-los em clientes repetidos, ou até quem sabe em “whales”, considerou-se que estes últimos teriam um nível de importância 2. Os níveis 1, 2 e 3 são uma escala de importância sendo 1 o mais importante e o 3 o menos importante.
Relativamente á associação criámos um novo ficheiro csv filtrado por País para podermos perceber pelo mesmos quais são as associações de produtos efetuadas.
Os 5 primeiros resultados da tabela com um IC de 85% ou superior são os seguintes:
Se comprar {PINK REGENCY TEACUP AND SAUCER, ROSES REGENCY TEACUP AND SAUCER} então compra => {GREEN REGENCY TEACUP AND SAUCER} Se comprar {PINK REGENCY TEACUP AND SAUCER, REGENCY CAKESTAND 3 TIER} então compra => {GREEN REGENCY TEACUP AND SAUCER} Se comprar {PINK REGENCY TEACUP AND SAUCER, REGENCY CAKESTAND 3 TIER} então compra => {ROSES REGENCY TEACUP AND SAUCER} Se comprar {SET 3 RETROSPOT TEA} então compra => {SUGAR} Se comprar {SUGAR} então compra => {SET 3 RETROSPOT TEA}
Podemos utilizar esta associação para reforçar a compra junto dos clientes, relembrando que estes produtos comprados em conjunto terão vantagens monetárias para os mesmos, reforçando assim a fidelização e a compra.
Invited Professor. LinkedIn. https://www.linkedin.com/in/joao-carlos-caldeira/↩︎